package com.bootdo.common.redis.lock;

import java.util.Collections;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

import com.bootdo.common.config.ApplicationContextRegister;

/**
 * @program: bootdo
 * @packageName: com.bootdo.common.redis.lock
 * @className: RedisLock
 * @description: 基于Redis分布式锁
 * @create: 2020-03-28 12:51
 */
public class RedisLock {

    private static final Logger logger = LoggerFactory.getLogger(RedisLock.class);


    private static final StringRedisTemplate REDIS_TEMPLATE = ApplicationContextRegister.getBean(StringRedisTemplate.class);
    private static final DefaultRedisScript<Long> LOCK_SCRIPT;
    private static final DefaultRedisScript<Object> UNLOCK_SCRIPT;
    static {
        // 加载释放锁的脚本
        LOCK_SCRIPT = new DefaultRedisScript<>();
        LOCK_SCRIPT.setScriptSource(new ResourceScriptSource(new ClassPathResource("config/lock.lua")));
        LOCK_SCRIPT.setResultType(Long.class);

        // 加载释放锁的脚本
        UNLOCK_SCRIPT = new DefaultRedisScript<>();
        UNLOCK_SCRIPT.setScriptSource(new ResourceScriptSource(new ClassPathResource("config/unlock.lua")));
    }
    /**
     * 获取锁
     * @param lockName 锁名称
     * @param releaseTime 超时时间(单位:秒)
     * @return key 解锁标识
     */
    public static String tryLock(String lockName,String releaseTime) {
        // 存入的线程信息的前缀，防止与其它JVM中线程信息冲突
        String key = UUID.randomUUID().toString();

        // 执行脚本
        Long result = REDIS_TEMPLATE.execute(
                LOCK_SCRIPT,
                Collections.singletonList(lockName),
                key + Thread.currentThread().getId(), releaseTime);

        // 判断结果
        if(result != null && result.intValue() == 1) {
            logger.info("获取Redis分布式锁："+result+"，【key】:"+key+"，【lockName】:"+lockName+"，【releaseTime】:"+releaseTime);
            return key;
        }else {
            logger.info("获取Redis分布锁失败，【lockName】:"+lockName+"，【releaseTime】:"+releaseTime);
            return null;
        }
    }
    /**
     * 释放锁
     * @param lockName 锁名称
     * @param key 解锁标识
     */
    public static void unlock(String lockName,String key) {
        logger.info("释放Redis分布式锁：，【key】:"+key+"，【lockName】:"+lockName);
        // 执行脚本
        REDIS_TEMPLATE.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(lockName),
                key + Thread.currentThread().getId(), null);
    }

}
